package com.cal.utms.report;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataset;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRResultSetDataSource;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRGraphics2DExporter;
import net.sf.jasperreports.engine.export.JRGraphics2DExporterParameter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.export.oasis.JROdsExporter;
import net.sf.jasperreports.engine.export.oasis.JROdtExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRPptxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

import com.cal.utms.util.ValueConvert;

public class ReportServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	/**
	 * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
	 * methods.
	 * 
	 * @throws ServletException
	 *             if a servlet-specific error occurs * @throws IOException if
	 *             an I/O error occurs
	 */
	@SuppressWarnings({ "rawtypes" })
	protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("started");
		// List of Cursors(ResultSets) for the report.
		final Map<String, ResultSet> cursors = new HashMap<String, ResultSet>();

		final ServletOutputStream servletOutputStream = response.getOutputStream();
		String reportName = null;
		Connection connection = null;

		// Set to expire far in the past.
		response.setHeader("Expires", "-1");
		// Set standard HTTP/1.1 no-cache headers.
		response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");

		try {

			URI uri = new URI(request.getRequestURI());
			final String requestURI = uri.toASCIIString();

			System.out.println("URI= " + requestURI);
			final int indexOfRptName = requestURI.indexOf("/ReportServlet/") + 15;
			if (indexOfRptName < 0) {
				reportName = null;
			}

			int lastIndexOfReportName = requestURI.indexOf('/', indexOfRptName);
			if (lastIndexOfReportName < indexOfRptName) {
				lastIndexOfReportName = requestURI.indexOf('?', indexOfRptName);
				if (lastIndexOfReportName < indexOfRptName) {
					lastIndexOfReportName = requestURI.length();
				}
			}

			System.out.println(indexOfRptName);
			System.out.println(lastIndexOfReportName);

			reportName = requestURI.substring(indexOfRptName, lastIndexOfReportName);

			System.out.println("report name is " + reportName);

			// if this is a image request, return the image.
			if (requestURI.indexOf("/report_images", indexOfRptName) > indexOfRptName) {
				final Object imgBytes = ((Map) request.getSession().getAttribute("report_images")).get(request.getParameter("img_name"));
				if (imgBytes != null && imgBytes instanceof byte[]) {
					response.getOutputStream().write((byte[]) imgBytes);
				} else {
					response.sendError(HttpServletResponse.SC_NOT_FOUND, "Image not available");
				}
				return;
			}

			// reset HTML image map
			request.getSession().setAttribute("report_images", new HashMap());

			// get session DB connection
			System.out.println("getting session connection");

			Class.forName("com.mysql.jdbc.Driver");
			connection = DriverManager.getConnection("jdbc:mysql://10.10.10.185:3306/utmsd", "root", "FISFE");
			if (connection == null)
				System.out.println("conn is null");
			else
				System.out.println("conn is NOT null");

			JasperReport jasperReport = null;
			try {
				JasperDesign jasperDesign = JRXmlLoader.load(request.getServletContext().getRealPath("/reports/" + reportName + ".jrxml"));
				jasperReport = JasperCompileManager.compileReport(jasperDesign);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				System.out.println("FINAL");
			}

			System.out.println(" complilled");
			final List<String> dataSets = new ArrayList<String>();
			{
				final JRDataset[] jrDatasets = jasperReport.getDatasets();
				if (jrDatasets != null) {
					for (JRDataset jrDataset : jrDatasets) {
						if (jrDataset != null)
							dataSets.add(jrDataset.getName());
					}
				}
			}

			HashMap<String, Object> reportParams = new HashMap<String, Object>();

			for (JRParameter jrParameter : jasperReport.getParameters()) {
				if (!jrParameter.isSystemDefined()) {
					System.out.println(jrParameter.getValueClassName());
					reportParams.put(jrParameter.getName(), valueConvert(jrParameter.getValueClassName(), jrParameter.getName(), request));
				}
			}

			// SET DATA SET PARAMETERS
			for (String ds : dataSets) {
				reportParams.put(ds, new JRResultSetDataSource(cursors.get(ds)));
				System.out.println("params>>" + cursors.get(ds));
			}
			System.out.println("after loop");
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, reportParams, connection);

			for (String dsName : cursors.keySet()) {
				ResultSet cursor = cursors.get(dsName);
				Statement statement = cursor.getStatement();
				cursor.close();
				statement.close();
			}
			final int noOfPages = jasperPrint.getPages().size();
			if (noOfPages > 0) {
				String outputType = "PDF";
				JRExporter exporter = null;
				if (outputType == null)
					outputType = "PDF";
				response.setHeader("Content-Disposition", "inline; filename=" + reportName + "_" + (System.currentTimeMillis() / 3600) + "." + outputType);
				if (outputType.equals("PDF")) {
					exporter = new JRPdfExporter();
					response.setContentType("application/pdf");
				} else if (outputType.equals("HTML")) {
					exporter = new JRHtmlExporter();
					exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, "report_images?img_name=");
					exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, request.getSession().getAttribute("report_images"));
					exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, false);
					response.setContentType("text/html");
				} else if (outputType.equals("RTF")) {
					exporter = new JRRtfExporter();
					response.setContentType("application/rtf");
				} else if (outputType.equals("XML")) {
					exporter = new JRXmlExporter();
					response.setContentType("text/xml");
				} else if (outputType.equals("CSV")) {
					exporter = new JRCsvExporter();
					response.setContentType("text/csv");
				} else if (outputType.equals("ODT")) {
					exporter = new JROdtExporter();
					response.setContentType("application/vnd.oasis.opendocument.text");
				} else if (outputType.equals("ODS")) {
					exporter = new JROdsExporter();
					response.setContentType("application/vnd.oasis.opendocument.spreadsheet");
				} else if (outputType.equals("DOCX")) {
					exporter = new JRDocxExporter();
					response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
				} else if (outputType.equals("XLS")) {
					exporter = new JRXlsExporter();
					response.setContentType("application/vnd.ms-excel");
				} else if (outputType.equals("XLSX")) {
					exporter = new JRXlsxExporter();
					response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
				} else if (outputType.equals("PPTX")) { // Does not work
					exporter = new JRPptxExporter();
					response.setContentType("application/vnd.openxmlformats-officedocument.presentationml.presentation");
				} else if (outputType.equals("GIF") || outputType.equals("JPEG") || outputType.equals("PNG") || outputType.equals("BMP")) {
					final float zm = (float) 2.0;
					final BufferedImage bufferedImage = new BufferedImage((int) (jasperPrint.getPageWidth() * zm) + 1, ((int) (jasperPrint.getPageHeight() * zm) + 1) * noOfPages,
							BufferedImage.TYPE_INT_RGB);
					exporter = new JRGraphics2DExporter();
					exporter.setParameter(JRGraphics2DExporterParameter.ZOOM_RATIO, zm);
					exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
					for (int i = 0; i < noOfPages; i++) {
						exporter.setParameter(JRGraphics2DExporterParameter.GRAPHICS_2D, bufferedImage.createGraphics());
						exporter.setParameter(JRGraphics2DExporterParameter.PAGE_INDEX, i);
						exporter.setParameter(JRGraphics2DExporterParameter.OFFSET_Y, ((int) (jasperPrint.getPageHeight() * zm) + 1) * i);
						exporter.exportReport();
						System.gc();
						Thread.sleep(200);
					}
					response.setContentType("image/" + outputType);
					ImageIO.write(bufferedImage, outputType, servletOutputStream);
				} else if (outputType.equals("PRINT")) {
					exporter = new JRDocxExporter();
					final File printOutFile = File.createTempFile(reportName + "_", ".docx");
					exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
					exporter.setParameter(JRExporterParameter.OUTPUT_FILE, printOutFile);
					exporter.exportReport();

					final Timer delTimer = new Timer(printOutFile.getName());
					delTimer.schedule(new TimerTask() {

						@Override
						public void run() {
							if (!printOutFile.delete()) {
								delTimer.schedule(this, 60000);
							}
						}
					}, 60000);
				} else {
					response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unknown Report Output Type");
					return;
				}
				if (!(outputType.equals("PRINT") || outputType.equals("GIF") || outputType.equals("JPEG") || outputType.equals("PNG") || outputType.equals("BMP"))) {
					exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
					exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
					exporter.exportReport();
				}
			} else {
				response.setContentType("text/html");
				servletOutputStream.print("<h1>No Pages</h1>");
			}

		} catch (RuntimeException ex) {

			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());

		} catch (Exception ex) {

			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());

		} finally {
			if (connection != null) {
				// DbConnector.closeSessionConnection(request.getSession(),
				// connection);
			}
			servletOutputStream.flush();
			servletOutputStream.close();
		}
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}

	private Object valueConvert(String valueClassName, String name, HttpServletRequest request) {

		String reqParamVal = request.getParameter(name);
		if (reqParamVal != null && reqParamVal.isEmpty()) {
			return null;
		}
		if (valueClassName.equals("java.lang.Integer")) {
			return ValueConvert.toInteger(reqParamVal);
		} else if (valueClassName.equals("java.lang.String")) {
			return reqParamVal;
		} else {
			return reqParamVal;
		}
	}
}